﻿using System;
using System.Collections.Generic;
using System.Linq;
using RrslLite.Net.Contracts;
using RrslLite.Net.Messages;

namespace RrslLite.Net.BatchImpl
{
    public class DuplexWcfBatch : Batch
    {
        private IAsyncWcfDuplexMessageService _communicationService;
        private IList<Message> Messages { get; set; }

        public DuplexWcfBatch(IAsyncWcfDuplexMessageService communicationService)
        {
            _communicationService = communicationService;
            Messages = new List<Message>();
        }

        protected override void DoExecuteBatch()
        {
            if (_communicationService.State == System.ServiceModel.CommunicationState.Faulted)
            {
                _communicationService =
                    Configuration.RrslLiteConfiguration.Instance.BatchBuilderConfiguration.
                        GetDuplexMessageProcessorProxy();
            }

            _communicationService.ReceiveReceived += CommunicationService_ReceiveReceived;
                
            _communicationService.BeginInvokeOperations(Messages.ToArray(), (a) => { }, null);
        }

        void CommunicationService_ReceiveReceived(object sender, InvokeOperationsAsyncCompletedArgs e)
        {
            ProcessResults(e);
        }

        protected virtual void ProcessResults(InvokeOperationsAsyncCompletedArgs e)
        {
            var responses = e.Result;
            try
            {
                foreach (var response in responses)
                {
                    var batchItem = Calls.SingleOrDefault(item => item.CorrelationId == response.CorrelationId);
                    if (batchItem == null || response.ContainsException)
                    {
                        continue;
                    }

                    batchItem.Callback(response.Result);
                }
            }

            finally
            {
                var results = from msg in responses
                              select new BatchCallResult
                              {
                                  CorrelationId = msg.CorrelationId,
                                  OperationContainerName = msg.OperationContainerName,
                                  OperationName = msg.OperationName,
                                  OperationParameters = msg.OperationParameters,
                                  Result = msg.Result,
                                  WasExceptionThrown = msg.ContainsException
                              };
                OnCompleted(results);
            }
        }

        public void AddMessage(Message msg)
        {
            Messages.Add(msg);
        }
    }
}